/*
 * pcicfg - PCI drivers & tools for accessing memory location, I/O ports and configuration space.
 * Copyright (C) 2013  Andrew Karasyov
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#ifndef _PCIDEVICEMANAGER_H_
#define _PCIDEVICEMANAGER_H_


#include <map>
#include <vector>
#include <string>
#include "../pcicfg_kernel/pcicfg.h"


class PCIDeviceDescription;


class PCIDeviceManager
{
public:

	/** Describes BDF mask to match against */
	typedef struct
	{
		unsigned short BDF;

		unsigned int BusExist    : 1;
		unsigned int DeviceExist : 1;
		unsigned int FuncExist   : 1;
		unsigned int reserved    : 5;
	} BDFMask;


	/** Enumerates possible value lengths */
	enum EValueLength
	{
		VALUE_LENGTH_BYTE = 0,
		VALUE_LENGTH_WORD,
		VALUE_LENGTH_DWORD
	};


	/** Describes register of different length */
	typedef struct
	{
		/** Offset is related to length. Can be in bytes, words or dwords. */
		unsigned short Offset;
		EValueLength   Length;
	} SRegister;

	/** Describes register assignment */
	typedef struct
	{
		SRegister Register;
		unsigned int Value;

	} SAssignment;

	PCIDeviceManager( const char* device_name );
	
	~PCIDeviceManager();

	static bool BuildBDFMask( std::string bdf_mask_str, BDFMask& bdf_mask );

	static bool BuildRegister( std::string register_str, SRegister& reg );

	static bool BuildAssignment( std::string assignment_str, SAssignment& assign );

	bool IsGood() const;

	void PrintHelp() const;

	void PrintBDF( unsigned short bdf ) const;

	bool ReadAllDevices();

	unsigned int GetDeviceCount();

	void PrintDeviceList( const BDFMask& bdf_mask );

	void PrintDeviceTree();

	void PrintAllDeviceCfgSpace( unsigned int req_cfg_size, const BDFMask& bdf_mask );

	void AssignRegisterOnDevices( const BDFMask& bdf_mask, const SAssignment& assign );

	void ReadRegisterOnDevices( const BDFMask& bdf_mask, const SRegister& reg );


private:

	typedef std::vector<PCIDeviceDescription> DeviceList;
	typedef std::map< unsigned short, DeviceList > DeviceTree;
	typedef DeviceList::iterator DeviceListIt;
	typedef DeviceTree::iterator DeviceTreeIt;

	DeviceList PCIDeviceList;

	int PciCfgDeviceHandle;

	void PrintDeviceTreeBus( unsigned short bus, DeviceTree& device_tree, unsigned int depth );

	void PrintDeviceCfgSpace( unsigned short bdf, unsigned int req_cfg_size );

	void AssignRegister( unsigned short bdf, const SAssignment& assign );

	void PrintRegister( unsigned short bdf, const SRegister& reg );

	bool MatchBDF( unsigned short bdf, const BDFMask& bdf_mask );
};


////////////////////////////////////////////////////////////////////////////////


inline bool PCIDeviceManager::IsGood() const
{
	return PciCfgDeviceHandle != 0;
}


////////////////////////////////////////////////////////////////////////////////


inline unsigned int PCIDeviceManager::GetDeviceCount()
{
	return PCIDeviceList.size();
}


////////////////////////////////////////////////////////////////////////////////


#endif // _PCIDEVICEMANAGER_H_
